#ifndef __M_QUEUE_H__
#define __M_QUEUE_H__
#include "../mqcommon/logger.hpp"
#include "../mqcommon/sqliter.hpp"
#include "../mqcommon/spliter.hpp"
#include "../mqcommon/filer.hpp"
#include "../mqcommon/message.pb.h"

/*
    1.实现队列类
    2.实现队列数据持久化管理类
    3.实现队列数据内存管理类
*/
#include <iostream>
#include <unordered_map>
#include <string>
#include <mutex>
#include <memory>
#include <sstream>

namespace zhong
{
    
    // 在数据库的消息队列存储单元，代表着队列的具体属性
    struct MessageQueue
    {
        using ptr = std::shared_ptr<MessageQueue>;

        std::string _name;
        bool _durable;
        bool _exclusive; // 是否独占
        bool _auto_delete;
        // std::unordered_map<std::string, std::string> _args_map;
        google::protobuf::Map<std::string, std::string> _args_map;  // 因为google::protobuf对应proto的协议的Map类型

        MessageQueue() {}
        MessageQueue(std::string name,
                     bool durable,
                     bool exclusive,
                     bool auto_delete,
                     const google::protobuf::Map<std::string, std::string> &args_map)
            : _name(name), _durable(durable), _exclusive(exclusive), _auto_delete(auto_delete), _args_map(args_map) {}

        // _args_map存储兼职对视，在存储数据库时，会组织一个格式进行存储
        void setArgs(const std::string &args)
        {
            // 解析args字符串，将内容存储到map中
            // 格式：key=val&key=val
            std::vector<std::string> sub_args;
            Spliter::split(args, "&", sub_args);
            for (auto &e : sub_args)
            {
                size_t pos = e.find("=");
                std::string key = e.substr(0, pos);
                std::string value = e.substr(pos + 1);
                // _args_map.insert(std::make_pair(key, value));
                _args_map[key] = value;
            }
        }
        // 将_args_map内容序列化后，返回一个字符串
        std::string getArgs()
        {
            std::string ret;
            for (auto &e : _args_map)
            {
                std::string part = e.first + "=" + e.second + "&";
                ret += part;
            }
            // ret.pop_back(); // 删除最后一个&
            return ret;
        }
    };

    using QueueMap = std::unordered_map<std::string, MessageQueue::ptr>;
    // 实现数据库持久化存储队列的具体属性
    class MessageQueueMapper
    {
    public:
        MessageQueueMapper(const std::string &data_base_file)
            : _sqliter(data_base_file)
        {
            std::string path = Filer::parentDirectory(data_base_file); // 获取父级目录
            Filer::createDirectory(path);                              // 创建目录
            assert(_sqliter.open());                                   // 创建数据库
            createTable();
        }
        void createTable()
        {
            // 构造表的创建语句
            std::string sql_create = "create table if not exists queue_table(name varchar(32) primary key,\
                                                                            durable int,\
                                                                            exclusive int,\
                                                                            auto_delete int,\
                                                                            args varchar(128));";
            if (_sqliter.exec(sql_create, nullptr, nullptr) == false)
            {
                ERR_LOG("创建队列数据库失败");
                abort(); // 退出程序
            }
        }
        void removeTable()
        {
            std::string sql_remove = "drop table if exists queue_table";
            if (_sqliter.exec(sql_remove, nullptr, nullptr) == false)
            {
                ERR_LOG("删除队列数据库失败");
                abort(); // 退出程序
            }
        }

        bool insert(MessageQueue::ptr &queue)
        {
            std::stringstream sql;
            sql << "insert into queue_table values(";
            sql << "'" << queue->_name << "', ";
            sql << queue->_durable << ", ";
            sql << queue->_exclusive << ", ";
            sql << queue->_auto_delete << ", ";
            sql << "'" << queue->getArgs() << "');";
            if (_sqliter.exec(sql.str(), nullptr, nullptr) == false)
            {
                INFO_LOG("添加队列数据失败, 错误原因[%s]", strerror(errno));
                return false; // 退出程序
            }
            return true;
        }
        bool remove(const std::string &name)
        {
            std::string sql_delete = "delete from queue_table where name='" + name + "';";
            if (_sqliter.exec(sql_delete, nullptr, nullptr) == false)
            {
                INFO_LOG("删除队列数据失败");
                return false; // 退出程序
            }
            return true;
        }
        // 查询交换机数据
        std::unordered_map<std::string, MessageQueue::ptr> getAllQueue()
        {
            // name - exchange来获取所以交换机数据
            std::unordered_map<std::string, MessageQueue::ptr> ret;
            std::string sql_select = "select name, durable, exclusive, auto_delete, args from queue_table";
            _sqliter.exec(sql_select, selectCallback, &ret);
            return ret;
        }

    private:
        static int selectCallback(void *args, int numcol, char **row, char **fields)
        {
            auto ret = (std::unordered_map<std::string, MessageQueue::ptr> *)args;
            auto queue = std::make_shared<MessageQueue>();
            // 按顺序添加queue数据到ret中
            queue->_name = row[0];
            queue->_durable = (bool)std::stoi(row[1]);
            queue->_exclusive = (bool)std::stoi(row[2]);
            queue->_auto_delete = (bool)std::stoi(row[3]);
            if (row[4] != nullptr)
                queue->setArgs(row[4]);

            ret->insert(std::make_pair(queue->_name, queue));
            return 0;
        }

    private:
        Sqliter _sqliter;
    };
    // 消息队列数据库存储单元队列的属性的内存级别的管理模块
    class MessageQueueManager
    {
    public:
        using ptr = std::shared_ptr<MessageQueueManager>;
        MessageQueueManager(const std::string &data_base_file)
            : _mapper(data_base_file)
        {
            _queues = _mapper.getAllQueue();
        }
        bool declareQueue(const std::string &name,
                          bool durable,
                          bool exclusive,
                          bool auto_delete,
                          const google::protobuf::Map<std::string, std::string> &args_map)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            // 查找队列是否存在
            auto it = _queues.find(name);
            if (it != _queues.end())
            {
                DEBUG_LOG("队列[%s]已存在，不需要再次声明", name.c_str());
                return false; // 表示当前的queues中包含名字为name的队列
            }
            auto queue = std::make_shared<MessageQueue>(name, durable, exclusive, auto_delete, args_map);
            if (queue->_durable == true)
            {
                _mapper.insert(queue);
            }
            _queues.insert(std::make_pair(queue->_name, queue));
            return true;
            
        }
        void deleteQueue(const std::string &name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _queues.find(name);
            if (it == _queues.end())
            {
                return; // 表示不存在name
            }
            if (it->second->_durable == true)
            {
                _mapper.remove(name);
            }
            _queues.erase(name);
        }
        MessageQueue::ptr selectQueue(const std::string &name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _queues.find(name);
            if (it == _queues.end())
            {
                return MessageQueue::ptr(); // 表示不存在name
            }
            return it->second;
        }
        bool exist(const std::string &name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _queues.find(name);
            if (it == _queues.end())
            {
                return false; // 表示不存在name
            }
            return true;
        }
        std::unordered_map<std::string, MessageQueue::ptr> allQueue()
        {
            std::unique_lock<std::mutex> lock(_mutex);
            return _queues;
        }
        size_t size()
        {
            std::unique_lock<std::mutex> lock(_mutex);
            return _queues.size();
        }
        void clear()
        {
            std::unique_lock<std::mutex> lock(_mutex);
            _mapper.removeTable();
            _queues.clear();
        }

    private:
        std::mutex _mutex;
        MessageQueueMapper _mapper;
        std::unordered_map<std::string, MessageQueue::ptr> _queues;
    };
};
#endif